package com.lmabbe.tenant.service.impls;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lmabbe.tenant.mapper.ModuleMapper;
import com.lmabbe.tenant.mapper.ModuleResourceMapper;
import com.lmabbe.tenant.objects.converter.ModuleConverter;
import com.lmabbe.tenant.objects.converter.ModuleResourceConverter;
import com.lmabbe.tenant.objects.entity.Module;
import com.lmabbe.tenant.objects.entity.ModuleResource;
import com.lmabbe.tenant.objects.vo.ModuleResourceTreeVO;
import com.lmabbe.tenant.objects.vo.ModuleResourceVO;
import com.lmabbe.tenant.objects.vo.ModuleTreeVO;
import com.lmabbe.tenant.service.ModuleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 系统模块
 *
 * @author lmabbe
 */
@Service
@RequiredArgsConstructor
public class ModuleServiceImpl extends ServiceImpl<ModuleMapper, Module>
        implements ModuleService {

    private final ModuleResourceMapper moduleResourceMapper;
    private final ModuleResourceConverter moduleResourceConverter;
    private final ModuleConverter moduleConverter;

    @Override
    public List<ModuleResourceVO> resources(Long moduleId) {
        List<ModuleResource> resources = moduleResourceMapper.selectList(
                moduleResourceMapper.createQueryWrapper()
                        .eq(ModuleResource::getModuleId, moduleId)
                        .eq(ModuleResource::getParentId, 0));
        return formatResourceVo(resources);
    }

    @Override
    public ModuleResource resource(Long resourceId) {
        return moduleResourceMapper.selectById(resourceId);
    }

    @Override
    public void addResource(ModuleResource resource) {
        this.moduleResourceMapper.insert(resource);
    }

    @Override
    public void delResource(Long resourceId) {
        this.moduleResourceMapper.deleteById(resourceId);
    }

    @Override
    public List<ModuleResourceVO> childResources(Long parentId) {
        List<ModuleResource> resources = moduleResourceMapper.selectList(
                moduleResourceMapper.createQueryWrapper()
                        .eq(ModuleResource::getParentId, parentId));
        return formatResourceVo(resources);
    }

    /**
     * 是否包含下级节点
     *
     * @param resourceId
     * @return
     */
    private Boolean hasChild(Long resourceId) {
        return moduleResourceMapper.selectCount(
                moduleResourceMapper.createQueryWrapper()
                        .eq(ModuleResource::getParentId, resourceId)) > 0;
    }

    /**
     * 格式化resourceVo
     *
     * @param resources
     * @return
     */
    private List<ModuleResourceVO> formatResourceVo(List<ModuleResource> resources) {
        List<ModuleResourceVO> resourceVos = new ArrayList<>();
        for (ModuleResource resource : resources) {
            ModuleResourceVO ModuleResourceVO = moduleResourceConverter.entity2Vo(resource);
            ModuleResourceVO.setHasChild(hasChild(resource.getResourceId()));
            resourceVos.add(ModuleResourceVO);
        }
        return resourceVos;
    }

    @Override
    public void editResource(ModuleResource resource) {
        this.moduleResourceMapper.updateById(resource);
    }

    @Override
    public List<ModuleTreeVO> allTree() {
        List<ModuleTreeVO> moduleTreeVOS = moduleConverter.list2TreeVos(this.list());
        List<ModuleResource> sysDicItems = moduleResourceMapper.selectList(Wrappers.emptyWrapper());
        List<ModuleResourceTreeVO> resourceTreeVos = moduleResourceConverter.dto2TreeVos(sysDicItems);

        List<ModuleResourceTreeVO> ModuleResourceTreeVOS = list2Tree(resourceTreeVos);

        for (ModuleTreeVO moduleTreeVO : moduleTreeVOS) {
            moduleTreeVO.setChild(
                    ModuleResourceTreeVOS.parallelStream().filter(s -> s.getModuleId().equals(moduleTreeVO.getModuleId()))
                            .collect(Collectors.toList())
            );
        }
        return moduleTreeVOS;
    }

    private List<ModuleResourceTreeVO> list2Tree(List<ModuleResourceTreeVO> sysDicItems) {
        List<ModuleResourceTreeVO> root = sysDicItems.parallelStream()
                .filter(s -> s.getParentId() == null || s.getParentId() == 0)
                .collect(Collectors.toList());

        for (ModuleResourceTreeVO resource : root) {
            findChild(sysDicItems, resource);
        }
        return root;
    }

    private void findChild(List<ModuleResourceTreeVO> sysDicItems, ModuleResourceTreeVO resource) {
        List<ModuleResourceTreeVO> child = sysDicItems.parallelStream()
                .filter(s -> s.getParentId() != null && s.getParentId().equals(resource.getResourceId()))
                .collect(Collectors.toList());
        if (child.size() == 0) {
            return;
        }
        resource.setChildren(child);
        for (ModuleResourceTreeVO ModuleResourceTreeVO : child) {
            findChild(sysDicItems, ModuleResourceTreeVO);
        }
    }
}
